package com.sihan.framework.etm.service.impl;

import com.framework.boot.shiro.PasswordDetail;
import com.framework.boot.shiro.PasswordEncoder;
import com.framework.constant.WebConstants;
import com.framework.exception.AuthException;
import com.framework.exception.BusinessException;
import com.framework.model.ApiResult;
import com.framework.model.PageResult;
import com.framework.mybatis.Condition;
import com.framework.mybatis.service.impl.BaseServiceImpl;
import com.framework.util.JsonUtils;
import com.framework.util.PageUtils;
import com.framework.util.WebUtils;
import com.framework.util.crypto.asymmetric.sm2.DataTamperException;
import com.framework.util.crypto.asymmetric.sm2.SM2;
import com.framework.util.crypto.asymmetric.sm2.SM2Coder;
import com.framework.util.crypto.symmetric.SM4;
import com.framework.util.date.DatePattern;
import com.framework.util.date.DateUtils;
import com.framework.util.lang.RegexpUtils;
import com.framework.web.websocket.WebSocketServer;
import com.github.pagehelper.PageHelper;
import com.sihan.framework.etm.common.AppConfiguration;
import com.sihan.framework.etm.common.CacheOperatorInfo;
import com.sihan.framework.etm.common.CommonBiz;
import com.sihan.framework.etm.common.RestBiz;
import com.sihan.framework.etm.common.util.EtmWebUtil;
import com.sihan.framework.etm.common.util.ImgUtils;
import com.sihan.framework.etm.dto.UserInfoDTO;
import com.sihan.framework.etm.entity.Log;
import com.sihan.framework.etm.entity.Org;
import com.sihan.framework.etm.entity.SecurityParam;
import com.sihan.framework.etm.entity.User;
import com.sihan.framework.etm.entity.UserRole;
import com.sihan.framework.etm.enums.CacheKeyName;
import com.sihan.framework.etm.enums.ErrorType;
import com.sihan.framework.etm.enums.FormatImgPre;
import com.sihan.framework.etm.enums.MqttSendCommandFunc;
import com.sihan.framework.etm.enums.RoleType;
import com.sihan.framework.etm.mapper.OrgMapper;
import com.sihan.framework.etm.mapper.RoleMapper;
import com.sihan.framework.etm.mapper.UserMapper;
import com.sihan.framework.etm.mapper.UserOrgMapper;
import com.sihan.framework.etm.mapper.UserRoleMapper;
import com.sihan.framework.etm.service.*;
import com.sihan.framework.etm.vo.LoginVO;
import com.sihan.framework.etm.vo.UserVO;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.Base64.Decoder;
import java.util.concurrent.CopyOnWriteArraySet;

@Service
@Slf4j
public class UserServiceImpl extends BaseServiceImpl<User, String> implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OrgMapper orgMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private UserOrgMapper userOrgMapper;

    @Autowired
    private RoleService roleService;
    @Autowired
    private LogService logService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private SecurityParamService securityParamService;

    @Autowired
    private SessionDAO sessionDAO;

    @Autowired
    private AppConfiguration appConfig;

    @Autowired
    private RestBiz restBiz;

    @Autowired
    private CommonBiz commonBiz;

    private static final String LOGIN_MAXSESSION = "在线用户已经达到并发会话的最大数量，请稍后再试";

    private static final String LOGIN_IP = "不允许的IP地址访问";
    private static final String LOGIN_TIME = "不允许的时间段访问";
    private static final String LOCK = "超过了尝试登录的次数，您的账户已经被锁定";
    private static final String AUTH = "用户名或密码错误";

    private static final String WRONG_PASSWORD = "密码错误,请核对后再输入";

    private static int imgsCompareTimes = 0;//脸部图片比对次数
    public static final Object lock = new Object();

    @Override
    public void register(String name, String username, String password, Boolean sex) {
        //判断用户名是否已经存在
        try {
            PasswordDetail passwordDetail = passwordEncoder.encode(password);
            String hashedPassword = passwordDetail.getHashedPassword();
            String salt = passwordDetail.getSalt();
            userMapper.insert(new User(username, hashedPassword, salt, name, sex));
        } catch (DuplicateKeyException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("该用户名或用户昵称已被注册");
        }
    }



    @Override
    public List<String> getSessionIdfindByOrgId(String orgId) {
        List<String> strings = userMapper.selectByorgId(orgId);
        List<Session> activeSessions = new ArrayList<>(sessionDAO.getActiveSessions());
        List<String> li = new ArrayList<>();
        for (Session session : activeSessions) {
            if (session != null && session.getId() != null) {
                User sessionUser = (User) session.getAttribute(WebConstants.CURRENT_USER);
                if (sessionUser != null) {
                    for (String string : strings) {
                        if (string.equals(sessionUser.getId())){
                            li.add(session.getId().toString());
                        }
                    }

                }
            }
        }
        return li;
    }


    @Transactional
    @Override
    public void updatePassword(String oldPassword, String newPassword) {
        User user = WebUtils.user();
        // 比较密码是否相同
        String oldPasswordSM4;
        String newPasswordSM4;
        try {
            oldPasswordSM4 = SM4.encode(oldPassword, SM4.getKey());
            newPasswordSM4 = SM4.encode(newPassword, SM4.getKey());
        } catch (IOException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("未知异常，联系管理员");
        }
        if (!user.getPassword().equals(oldPasswordSM4)) {
            throw new BusinessException("原密码错误");
        }

        if (oldPassword.equals(newPassword)) {
            throw new BusinessException("新密码不能和旧密码相同");
        }

        if (newPassword.indexOf(user.getUsername()) >= 0) {
            throw new BusinessException("新密码不能包含或等于用户名");
        }

        user.setPassword(newPasswordSM4);
        user.setUpdatePsdTime(new Date());
        userMapper.updateById(user);
    }

    @Transactional
    @Override
    public boolean updateInfo(User user) {
        try {
            String username = WebUtils.username();
            return userMapper.update(new Condition<>(user).eq("username", username));
        } catch (DuplicateKeyException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("该用户昵称已被注册");
        }
    }

    @Override
    public PageResult<UserVO> pageUser(UserInfoDTO dto) {
        PageHelper.startPage(dto);
        String orgIds = (String) CacheOperatorInfo.getMapValue(EtmWebUtil.userId(), null);
        List<UserVO> data = userMapper.selectPage(dto.getName(), dto.getUsername(), dto.getRole(), dto.getCode(),
                dto.getId(), dto.getUserId(), dto.getRoleId(), orgIds.split(","));
        if (data.size() > 0) {
            for (UserVO vo : data) {
                List<String> strings = userMapper.selectRoleIds(vo.getId());
                vo.setRoleIds(strings);
            }
        }
        return PageUtils.toPageResult(data);
    }

    @Override
    @Transactional
    public void addUser(User user, List<String> roleIds, String orgId) {
        String dePsd = user.getPassword();
//    try {
//      dePsd = SM2Coder.decode(user.getPassword());
//    } catch (IOException e) {
//      e.printStackTrace();
//      throw new BusinessException("未知异常，联系管理员");
//    } catch (DataTamperException e) {
//      e.printStackTrace();
//      throw new BusinessException("数据在传输过程中被恶意篡改，请确保环境是否安全");
//    }

        if (StringUtils.isBlank(dePsd) || !RegexpUtils.isPassword(dePsd)) {
            throw new BusinessException("密码只能是8-20位必须符合由大写字母、小写字母、数字、特殊字符至少其中三种组成");
        }

        if (dePsd.equals(user.getUsername()) || dePsd.indexOf(user.getUsername()) != -1) {
            throw new BusinessException("密码不能与用户名相同或者包含用户名");
        }

        if (StringUtils.isNotBlank(user.getLoginIp())) {
            if (!RegexpUtils.isIPAddr(user.getLoginIp())) {
                throw new BusinessException("IP地址格式错误");
            }
        }

        if (user.getAccessStartTime() != null && user.getAccessEndTime() != null) {
            if (user.getAccessStartTime().after(user.getAccessEndTime())) {
                throw new BusinessException("访问起始时间必须小于访问结束时间");
            }
        }

        try {
            user.setPassword(SM4.encode(dePsd, SM4.getKey()));
        } catch (IOException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("未知异常，联系管理员");
        }

        checkRolr(roleIds);

        try {
            user.setUserType(0);
            Org org = orgMapper.selectById(orgId);
            user.setCompanyCode(org.getCompanyCode());
            userMapper.insert(user);
            if (roleIds != null && roleIds.size() > 0) {
                // 添加用户角色权限
                userRoleMapper.insertUserRole(user.getId(), roleIds, new Date(), WebUtils.username());
            }
//      if(orgId != null) {//添加用户单位
//    	  UserOrg userOrg = new UserOrg();
//    	  userOrg.setUserId(user.getId());
//    	  userOrg.setOrgId(orgId);
//    	  userOrg.setCreateTime(new Date());
//    	  userOrg.setCreateUser(WebUtils.username());
//    	  userOrgMapper.insert(userOrg);
//      }


            //添加临时账号期限定时任务,XX个月后到期应转为休眠状态
            if (user.getUserType().intValue() == 1) {
                SecurityParam sp = securityParamService.getSecurity();
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(user.getCreateTime());
                calendar.add(Calendar.MONTH, sp.getTempAccount());
            }

            //mailService.sendHtmlMail(user.getEmail(), "初始化密码", "<h3>你的初始化密码为：[" + dePsd + "]，请及时登录系统修改密码！</h3>");

        } catch (DuplicateKeyException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("该用户名、用户昵称或者邮箱已被注册");
        }
    }

    @Override
    @Transactional
    //@CacheEvict(cacheNames = "authorizationCache", key = "#result", condition = "#result != null")
    public void updateUser(User user, List<String> roleIds, String orgId) {
        User oldUser = getUserById(user.getId());
        if (oldUser == null) {
            throw new BusinessException("更新用户id不存在");
        }

        try {
            userMapper.updateById(user);
            // 更新用户角色信息
            upUserRole(roleIds, user.getId());
            //更新用户单位
        } catch (DuplicateKeyException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("该用户昵称或邮箱已被注册");
        } catch (BusinessException e) {
            log.error("用户管理异常", e);
            throw e;
        }
    }

    /**
     * 更新用户角色信息
     *
     * @param roleIds
     * @param userId
     * @return void
     * @author 张荣英
     * @date Jul 29, 2019 4:48:43 PM
     */
    @Override
    public void upUserRole(List<String> roleIds, String userId) {
        checkRolr(roleIds);
        Set<String> selectedRoleIds = userRoleMapper.selectRoleIdsByUserId(userId);
        for (String roleId : roleIds) {
            if (selectedRoleIds.contains(roleId)) {
                selectedRoleIds.remove(roleId);
            } else {
                if (roleMapper.selectById(roleId) == null) {
                    throw new BusinessException("角色Id不存在");
                }
                UserRole userRole = new UserRole();
                userRole.setUserId(userId);
                userRole.setRoleId(roleId);
                userRoleMapper.insert(userRole);
            }
        }
        for (String selectedRoleId : selectedRoleIds) {
            UserRole userRole = new UserRole();
            userRole.setIsDelete(true);
            Condition<?> condition = new Condition<>(userRole)
                    .eq("user_id", userId)
                    .eq("role_id", selectedRoleId)
                    .eq("is_delete", false);
            userRoleMapper.update(condition);
        }
    }

    private void checkRolr(List<String> roleIds) {
        if (CollectionUtils.isNotEmpty(roleIds)) {
//      if(roleIds.size() > 1) {
//        throw new BusinessException("至多选择一个角色");
//      }
            for (String roleId : roleIds) {
                if (roleMapper.selectById(roleId) == null) {
                    throw new BusinessException("角色Id不存在");
                }
            }
        }
    }

    @Override
    @Transactional
    //@CacheEvict(cacheNames = "authorizationCache", allEntries = true)
    public void deleteUserByUserIds(List<String> userIds) {
        for (String userId : userIds) {
            User user = new User();
            user.setId(userId);
            user.setIsDelete(true);
            user.setState(-1);
            userMapper.updateById(user);
            // 更新用户权限信息
      /*UserRole userRole = new UserRole();
      userRole.setIsDelete(true);
      Condition condition = new Condition<>(userRole)
          .eq("user_id", userId)
          .eq("is_delete", false);
      userRoleMapper.update(condition);*/
        }
    }


    @Transactional
    @Override
    public void activeUserByUserId(String userId) {
        User user = getUserById(userId);
        if (user == null) {
            throw new BusinessException("激活用户id不存在");
        } else if (user.getState().intValue() == 0) {
            throw new BusinessException("该用户已是激活状态");
        }

        User u = new User();
        u.setId(userId);
        u.setState(0);
        u.setHasActive(true);
        userMapper.updateById(u);
    }

    @Transactional
    @Override
    public void unlockUserByUserId(String userId) {
        User user = getUserById(userId);
        if (user == null) {
            throw new BusinessException("解锁用户id不存在");
        } else if (!user.getLocked()) {
            throw new BusinessException("该用户不是锁定状态");
        }

        User u = new User();
        u.setId(userId);
        u.setLocked(false);
        userMapper.unlockUserByUserId(u);
    }

    @Transactional
    @Override
    public LoginVO login(String username, String password, String hashId) throws AuthException {
        String dePassword;
        String passwordSM4;
        LoginVO result = new LoginVO();
        try {
            //dePassword = SM2Coder.decode(password);
            //passwordSM4 = SM2Coder.decodeSMS4(password);
            //dePassword = "abcd_1234";

            //Decoder decoder = Base64.getDecoder();
            //byte[] bytes = decoder.decode(password.getBytes());
            //System.out.println("BASE64解密：" + new String(bytes));

            dePassword = SM4.decode(password, SM4.getKey());
            passwordSM4 = SM4.encode(dePassword, SM4.getKey());
        } catch (Exception e) {
            log.error("用户管理异常", e);
            throw new BusinessException("未知异常，联系管理员");
        }

        if (!RegexpUtils.isPassword(dePassword)) {
            throw new BusinessException("密码只能是8-20位必须符合由大写字母、小写字母、数字、特殊字符至少其中三种组成");
        }
        User user = userMapper.selectOne(new Condition<>(new User(username)));
        if (user == null) {
            throw new UnknownAccountException();
        } else {
            if (user.getState() != null) {
                if (user.getState().intValue() == -1) {//注销
                    throw new BusinessException("此账号已注销");
                } else if (user.getState().intValue() == 1) {//休眠
                    throw new BusinessException("此账号处于休眠中");
                }
            }
            String password1 = user.getPassword();
            if (!passwordSM4.equals(password1)) {
                throw new AuthException(WRONG_PASSWORD);
            }
            // 获取当前的Subject
            Subject subject = SecurityUtils.getSubject();

            String currentIp = subject.getSession().getHost();
            //ip记录
            if (StringUtils.isNotBlank(user.getLoginIp())) {
                if (!user.getLoginIp().equals(currentIp)) {
                    LocalDateTime localDateTime = LocalDateTime.now();
                    String opera = "IP地址异常";
                    StringBuffer content = new StringBuffer();
                    try {
                        content.append("【").append(user.getUsername()).append("】").append(opera);
                        content.append("： “").append(user.getUsername()).append("” ").append(DateUtils.formatDateTime(localDateTime, DatePattern.DATETIME))
                                .append(" 在IP地址为<").append(currentIp).append(">的客户端试图登录，为非允许的IP地址");
                    } catch (Exception e1) {
                        log.error("用户管理异常", e1);
                    }

                    Log log = new Log(currentIp, opera, content.toString(), false, 2, ErrorType.GENERAL.getValue(), user.getUsername(), new Date());
                    logService.insert(log);
                    sendErrorMsg(log);

                    throw new AuthException(LOGIN_IP);
                }
            }

            //当前时间是否允许访问
            Date now = new Date();
            if (user.getAccessStartTime() == null && user.getAccessEndTime() != null) {
                if (now.after(user.getAccessEndTime())) {
                    throw new BusinessException(LOGIN_TIME);
                }
            } else if (user.getAccessStartTime() != null && user.getAccessEndTime() == null) {
                if (now.before(user.getAccessStartTime())) {
                    throw new BusinessException(LOGIN_TIME);
                }
            } else if (user.getAccessStartTime() != null && user.getAccessEndTime() != null) {
                if (now.before(user.getAccessStartTime()) || now.after(user.getAccessEndTime())) {
                    throw new BusinessException(LOGIN_TIME);
                }
            }

            if (!subject.isAuthenticated()) {
                SecurityParam sp = securityParamService.getSecurity();
                Collection<Session> sessions = sessionDAO.getActiveSessions();
                Map<String, Session> map = new HashMap<>();

                if (sessions != null && sessions.size() > 0) {
                    for (Session session : sessions) {
                        if (session != null && session.getId() != null) {
                            User sessionUser = (User) session.getAttribute(WebConstants.CURRENT_USER);
                            if (sessionUser != null) {
                                map.put(sessionUser.getUsername(), session);
                            }
                        }
                    }
                }

                //当前在线会话数等于最大会话并发数，禁止登陆
                if (sp != null && sp.getMaxSession() != null && sp.getMaxSession().intValue() > 0) {
                    if (map.size() >= sp.getMaxSession().intValue()) {
                        throw new BusinessException(LOGIN_MAXSESSION);
                    }
                }

                try {
                    UsernamePasswordToken token = new UsernamePasswordToken(username, passwordSM4);
                    subject.login(token);
                    //更新登录时间（数据库对应上次最后访问时间，连续登录失败次数清0）
                    User upUser = new User();
                    upUser.setId(user.getId());
                    upUser.setLastAccessTime(new Date());
                    upUser.setLoginFault(0);
                    userMapper.updateById(upUser);

                    subject.getSession().setAttribute("HASH_ID", hashId);
                    subject.getSession().setAttribute(WebConstants.CURRENT_USER, user);
                    //设置session过期时间

//                    if (sp != null && sp.getGlobalSessionTimeout() != null && sp.getGlobalSessionTimeout().intValue() > 0 && sp.getGlobalSessionTimeout().intValue() <= 30) {
//                        subject.getSession().setTimeout(sp.getGlobalSessionTimeout().intValue() * 60 * 1000L);
//                    }
                    subject.getSession().setTimeout(-100000L);
                    result.setSessionId(subject.getSession().getId().toString());

                    commonBiz.setUserOrgIds(user.getId(), user.getOrgId());

                } catch (Exception e) {
                    log.error("用户管理异常", e);
                    if (e instanceof IncorrectCredentialsException) {
                        //更新登录失败次数+1
                        userMapper.upUserLoginFault(user.getId());

                        if (user.getLoginFault().intValue() >= 1) {//连续登录失败告警
                            LocalDateTime localDateTime = LocalDateTime.now();
                            String opera = "连续登录失败";
                            StringBuffer content = new StringBuffer();
                            try {
                                content.append("【").append(user.getUsername()).append("】").append(opera);
                                content.append("： “").append(user.getUsername()).append("” ").append(DateUtils.formatDateTime(localDateTime, DatePattern.DATETIME))
                                        .append(" 在IP地址为<").append(currentIp).append(">的客户端已经连续登录失败")
                                        .append(user.getLoginFault().intValue() + 1).append("次");
                            } catch (Exception e2) {
                                log.error("用户管理异常", e2);
                            }

                            Log log = new Log(currentIp, opera, content.toString(), false, 2, ErrorType.TRIVIAL.getValue(), user.getUsername(), new Date());
                            logService.insert(log);
                            sendErrorMsg(log);
                        }

                        if (user.getLoginFault().intValue() + 1 >= sp.getFaultNum().intValue()) {
                            User upUser = new User();
                            upUser.setId(user.getId());
                            Calendar calendar = Calendar.getInstance();
                            upUser.setLockTime(calendar.getTime());
                            upUser.setLocked(true);
                            userMapper.updateById(upUser);
                            //锁定用户
                            //解锁定时任务
                            calendar.add(Calendar.MINUTE, sp.getLockTime());
                            throw new AuthException(LOCK);

                        }

                        throw new AuthException(AUTH);
                    } else if (e instanceof UnknownAccountException) {
                        throw new UnknownAccountException();
                    } else if (e instanceof LockedAccountException) {
                        throw new LockedAccountException();
                    } else {
                        throw new BusinessException("登录失败,联系管理员");
                    }

                }
            } else {
                result.setSessionId(subject.getSession().getId().toString());
            }
        }
        return result;
    }


    @Override
    public LoginVO wxlogin(String username, String password) throws AuthException {
        String passwordSM4;
        LoginVO result = new LoginVO();
        try {

            passwordSM4 = SM4.encode(password, SM4.getKey());
        } catch (Exception e) {
            log.error("用户管理异常", e);
            throw new BusinessException("未知异常，联系管理员");
        }

        User user = userMapper.selectOne(new Condition<>(new User(username)));
        if (user == null) {
            throw new UnknownAccountException();
        } else {
            if (user.getState() != null) {
                if (user.getState().intValue() == -1) {//注销
                    throw new BusinessException("此账号已注销");
                } else if (user.getState().intValue() == 1) {//休眠
                    throw new BusinessException("此账号处于休眠中");
                }
            }
            String password1 = user.getPassword();
            if (!passwordSM4.equals(password1)) {
                throw new AuthException(WRONG_PASSWORD);
            }
            // 获取当前的Subject
            Subject subject = SecurityUtils.getSubject();

            String currentIp = subject.getSession().getHost();
            //ip记录
            if (StringUtils.isNotBlank(user.getLoginIp())) {
                if (!user.getLoginIp().equals(currentIp)) {
                    LocalDateTime localDateTime = LocalDateTime.now();
                    String opera = "IP地址异常";
                    StringBuffer content = new StringBuffer();
                    try {
                        content.append("【").append(user.getUsername()).append("】").append(opera);
                        content.append("： “").append(user.getUsername()).append("” ").append(DateUtils.formatDateTime(localDateTime, DatePattern.DATETIME))
                                .append(" 在IP地址为<").append(currentIp).append(">的客户端试图登录，为非允许的IP地址");
                    } catch (Exception e1) {
                        log.error("用户管理异常", e1);
                    }

                    Log log = new Log(currentIp, opera, content.toString(), false, 2, ErrorType.GENERAL.getValue(), user.getUsername(), new Date());
                    logService.insert(log);
                    sendErrorMsg(log);

                    throw new AuthException(LOGIN_IP);
                }
            }

            //当前时间是否允许访问
            Date now = new Date();
            if (user.getAccessStartTime() == null && user.getAccessEndTime() != null) {
                if (now.after(user.getAccessEndTime())) {
                    throw new BusinessException(LOGIN_TIME);
                }
            } else if (user.getAccessStartTime() != null && user.getAccessEndTime() == null) {
                if (now.before(user.getAccessStartTime())) {
                    throw new BusinessException(LOGIN_TIME);
                }
            } else if (user.getAccessStartTime() != null && user.getAccessEndTime() != null) {
                if (now.before(user.getAccessStartTime()) || now.after(user.getAccessEndTime())) {
                    throw new BusinessException(LOGIN_TIME);
                }
            }

            if (!subject.isAuthenticated()) {
                SecurityParam sp = securityParamService.getSecurity();
                Collection<Session> sessions = sessionDAO.getActiveSessions();
                Map<String, Session> map = new HashMap<>();

                if (sessions != null && sessions.size() > 0) {
                    for (Session session : sessions) {
                        if (session != null && session.getId() != null) {
                            User sessionUser = (User) session.getAttribute(WebConstants.CURRENT_USER);
                            if (sessionUser != null) {
                                map.put(sessionUser.getUsername(), session);
                            }
                        }
                    }
                }
                //当前在线会话数等于最大会话并发数，禁止登陆
                if (sp != null && sp.getMaxSession() != null && sp.getMaxSession().intValue() > 0) {
                    if (map.size() >= sp.getMaxSession().intValue()) {
                        throw new BusinessException(LOGIN_MAXSESSION);
                    }
                }
                try {
                    UsernamePasswordToken token = new UsernamePasswordToken(username, passwordSM4);
                    subject.login(token);
                    //更新登录时间（数据库对应上次最后访问时间，连续登录失败次数清0）
                    User upUser = new User();
                    upUser.setId(user.getId());
                    upUser.setLastAccessTime(new Date());
                    upUser.setLoginFault(0);
                    userMapper.updateById(upUser);
                    subject.getSession().setAttribute("HASH_ID", null);
                    subject.getSession().setAttribute(WebConstants.CURRENT_USER, user);
                    //设置session过期时间
                    subject.getSession().setTimeout(-100000L);
                    result.setSessionId(subject.getSession().getId().toString());
                    commonBiz.setUserOrgIds(user.getId(), user.getOrgId());
                } catch (Exception e) {
                    log.error("用户管理异常", e);
                    if (e instanceof IncorrectCredentialsException) {
                        //更新登录失败次数+1
                        userMapper.upUserLoginFault(user.getId());

                        if (user.getLoginFault().intValue() >= 1) {//连续登录失败告警
                            LocalDateTime localDateTime = LocalDateTime.now();
                            String opera = "连续登录失败";
                            StringBuffer content = new StringBuffer();
                            try {
                                content.append("【").append(user.getUsername()).append("】").append(opera);
                                content.append("： “").append(user.getUsername()).append("” ").append(DateUtils.formatDateTime(localDateTime, DatePattern.DATETIME))
                                        .append(" 在IP地址为<").append(currentIp).append(">的客户端已经连续登录失败")
                                        .append(user.getLoginFault().intValue() + 1).append("次");
                            } catch (Exception e2) {
                                log.error("用户管理异常", e2);
                            }

                            Log log = new Log(currentIp, opera, content.toString(), false, 2, ErrorType.TRIVIAL.getValue(), user.getUsername(), new Date());
                            logService.insert(log);
                            sendErrorMsg(log);
                        }

                        if (user.getLoginFault().intValue() + 1 >= sp.getFaultNum().intValue()) {
                            User upUser = new User();
                            upUser.setId(user.getId());
                            Calendar calendar = Calendar.getInstance();
                            upUser.setLockTime(calendar.getTime());
                            upUser.setLocked(true);
                            userMapper.updateById(upUser);
                            //锁定用户
                            //解锁定时任务
                            calendar.add(Calendar.MINUTE, sp.getLockTime());
                            throw new AuthException(LOCK);

                        }

                        throw new AuthException(AUTH);
                    } else if (e instanceof UnknownAccountException) {
                        throw new UnknownAccountException();
                    } else if (e instanceof LockedAccountException) {
                        throw new LockedAccountException();
                    } else {
                        throw new BusinessException("登录失败,联系管理员");
                    }

                }
            } else {
                result.setSessionId(subject.getSession().getId().toString());
            }
        }
        return result;
    }

    @Transactional
    @Override
    public void resetPassword(String userId, String newPsd) {
        User user = getUserById(userId);
        if (user == null) {
            throw new BusinessException("被重置密码的用户id不存在");
        }
        String newPasswordSM4;
        try {
            newPasswordSM4 = SM4.encode(newPsd, SM4.getKey());
        } catch (IOException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("未知异常，联系管理员");
        }
        if (newPsd.indexOf(user.getUsername()) >= 0) {
            throw new BusinessException("新密码不能包含或等于用户名");
        }
        user.setPassword(newPasswordSM4);
        if (!userMapper.resetUserPsdByUserId(user)) {
            throw new BusinessException("重置密码失败，联系管理员");
        }
    }

    @Override
    public boolean identuser(String password) {
        String dePsd;
        try {
            dePsd = SM2Coder.decodeSMS4(password);
        } catch (IOException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("未知异常，联系管理员");
        } catch (DataTamperException e) {
            log.error("用户管理异常", e);
            throw new BusinessException("数据在传输过程中被恶意篡改，请确保环境是否安全");
        }
        if (StringUtils.isBlank(dePsd)) {
            throw new BusinessException("鉴别失败");
        }
        User user = WebUtils.user();
        return dePsd.equals(user.getPassword());
    }

    private void sendErrorMsg(Log log1) {
        CopyOnWriteArraySet<WebSocketServer> webSocketSet = WebSocketServer.getWebSocketSet();
        if (webSocketSet != null && webSocketSet.size() > 0) {
            for (WebSocketServer ws : webSocketSet) {
                if (ws.getSession().isOpen()) {
                    Set<String> roles = roleService.selectRolesByUsername(ws.getSid());
                    if (roles != null && roles.contains(RoleType.AUDITMANAGER.getValue())) {
                        try {
                            ws.sendMessage(JsonUtils.toJsonString(log1));
                        } catch (IOException e) {
                            log.error("用户管理异常", e);
                        }
                    }
                }
            }
        }
    }

    /**
     * 根据用户id获取用户
     *
     * @param userId
     * @return
     */
    private User getUserById(String userId) {
        return userMapper.selectOne(new Condition<>(new User(userId, null, false)));
    }

    /**
     * 查询通知数量
     */
    @Override
    public int getNoticeNum() {
        return userMapper.getNoticeNum(EtmWebUtil.userId());
    }

    @Override
    public List<Map<String, String>> getUserList(String companyId) {
        Org org = orgMapper.selectById(companyId);
        return userMapper.getUserList(org.getCompanyCode());
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public ApiResult getOperatorUserIdFromHardware(Integer type, UserVO param) {
        //正式上线时改为
        String validateUserId = (String) CacheOperatorInfo.getMapValue(CacheKeyName.VALIDATED_USER_ID.getValue(), null);
        if (!StringUtils.isBlank(validateUserId)) {
            commonBiz.sendIcCardEnd();
            return ApiResult.success(selectUserByUserId(validateUserId));
        }
        CacheOperatorInfo.flushCashMap();
        User u = null;
        //ICCARD 验证
        if (type == 1) {
            //开启iccard读取
            commonBiz.sendIcCardStart();
            CacheOperatorInfo.setMapValue(CacheKeyName.CHECK_IS_READ_CARD_FLAG.getValue(), "1");
            CacheOperatorInfo.setMapValue(CacheKeyName.IC_CARD_INFO.getValue(), CacheKeyName.IC_CARD_INFO.getValue());
            Date start = new Date();
            Boolean hasExpired = false;
            Boolean hasDone = false;
            String icCard = null;
            while (!hasDone && !hasExpired) {
                icCard = (String) CacheOperatorInfo.getMapValue(CacheKeyName.IC_CARD_INFO.getValue(), CacheKeyName.IC_CARD_INFO.getValue());
                if (!StringUtils.isBlank(icCard) && !icCard.equals(CacheKeyName.IC_CARD_INFO.getValue())) {
                    hasDone = true;
                    CacheOperatorInfo.setMapValue(CacheKeyName.IC_CARD_INFO.getValue(), CacheKeyName.IC_CARD_INFO.getValue());
                    break;
                }
                Calendar now = Calendar.getInstance();
                now.add(Calendar.SECOND, -appConfig.getWaitOperatorSeconds());
                if (start.compareTo(now.getTime()) < 0) {
                    hasExpired = true;
                }
            }
            CacheOperatorInfo.setMapValue(CacheKeyName.CHECK_IS_READ_CARD_FLAG.getValue(), CacheKeyName.CHECK_IS_READ_CARD_FLAG.getValue());
            CacheOperatorInfo.setMapValue(CacheKeyName.IC_CARD_INFO.getValue(), CacheKeyName.IC_CARD_INFO.getValue());
            u = userMapper.selectOne(new Condition<User>().eq("ic_card", icCard));
            if (null != u) {
                CacheOperatorInfo.setMapValue(CacheKeyName.VALIDATED_USER_ID.getValue(), u.getId());
                if (appConfig.getDistinguishOpenDoor() && null != param && null != param.getOpenDoor() && param.getOpenDoor()) {
                    commonBiz.sendCommandToDevice(MqttSendCommandFunc.COMMAND_2000.getValue());
                }
                //iccard关闭读取
                commonBiz.sendIcCardEnd();
                return ApiResult.success(selectUserByUserId(u.getId()));
            }
            return ApiResult.fail("请检查ICCard信息是否录入系统");
        }
        //人脸验证
        if (type == 2) {
            //去调用验证是否是脸部验证接口
            String validatedImg = this.validateIsFaceImg(param.getImg());
            if (!StringUtils.isBlank(validatedImg)) {
                List<User> users = userMapper.selectList(new Condition<User>());
                for (User user : users) {
                    //去调用比对的接口
                    if (!StringUtils.isBlank(user.getFaceImgs())) {
                        String face64 = ImgUtils.getImgBase64Str(appConfig.getRootPath() + FormatImgPre.PRE_FACE.getValue() + user.getFaceImgs());
                        Boolean result = false;
                        if (null != face64) {
                            result = this.compareFaceImg(face64, validatedImg);
                        }
                        log.info(user.getId() + "比对结果-----------------------：" + result);
                        if (result) {
                            CacheOperatorInfo.setMapValue(CacheKeyName.VALIDATED_USER_ID.getValue(), user.getId());
                            log.info("---------------------------成功！");
                            if (appConfig.getDistinguishOpenDoor() && null != param && null != param.getOpenDoor() && param.getOpenDoor()) {
                                commonBiz.sendCommandToDevice(MqttSendCommandFunc.COMMAND_2000.getValue());
                            }
                            return ApiResult.success(selectUserByUserId(user.getId()));
                        }
                    }
                }
            }
            log.info("-------------------------失败！");
            return ApiResult.fail("人脸识别失败");
        }
        log.info("-------------------------失败！");
        return ApiResult.fail("识别失败");
    }

    @SuppressWarnings("rawtypes")
    @Override
    public ApiResult updateIcCardInfo(String userId) {
        //开启ic卡读写器
        commonBiz.sendIcCardStart();
        String icCard = null;
        User u = userMapper.selectById(userId);
        if (u != null) {
            CacheOperatorInfo.setMapValue(CacheKeyName.CHECK_IS_READ_CARD_FLAG.getValue(), "1");
            CacheOperatorInfo.setMapValue(CacheKeyName.IC_CARD_INFO.getValue(), CacheKeyName.IC_CARD_INFO.getValue());
            Date start = new Date();
            Boolean hasExpired = false;
            Boolean hasDone = false;
            while (!hasDone && !hasExpired) {
                icCard = (String) CacheOperatorInfo.getMapValue(CacheKeyName.IC_CARD_INFO.getValue(), CacheKeyName.IC_CARD_INFO.getValue());
                if (!StringUtils.isBlank(icCard) && !icCard.equals(CacheKeyName.IC_CARD_INFO.getValue())) {
                    hasDone = true;
                    CacheOperatorInfo.setMapValue(CacheKeyName.IC_CARD_INFO.getValue(), CacheKeyName.IC_CARD_INFO.getValue());
                    break;
                }
                Calendar now = Calendar.getInstance();
                now.add(Calendar.SECOND, -appConfig.getWaitOperatorSeconds());
                if (start.compareTo(now.getTime()) < 0) {
                    hasExpired = true;
                }
            }
            //缓存复位
            CacheOperatorInfo.setMapValue(CacheKeyName.CHECK_IS_READ_CARD_FLAG.getValue(), CacheKeyName.CHECK_IS_READ_CARD_FLAG.getValue());
            CacheOperatorInfo.setMapValue(CacheKeyName.IC_CARD_INFO.getValue(), CacheKeyName.IC_CARD_INFO.getValue());
            if (hasDone) {
                @SuppressWarnings("unchecked")
                User findUser = userMapper.selectOne(new Condition<User>().eq("ic_card", icCard));
                if (null != findUser) {
                    return ApiResult.fail("此卡已分配，勿重复录入");
                }
                u.setIcCard(icCard);
                userMapper.updateById(u);
                //关闭ic卡读写器
                commonBiz.sendIcCardEnd();
                return ApiResult.success("操作成功");
            }
        }
        return ApiResult.fail("操作失败");
    }

    @SuppressWarnings("rawtypes")
    @Override
    public ApiResult updateFaceInfo(String userId, String face) {
        if (StringUtils.isBlank(userId)) {
            return ApiResult.fail("操作失败请重试");
        }
        String needCheckUserId = (String) CacheOperatorInfo.getMapValue(CacheKeyName.CAHCE_NEED_CHECK_FACE_USER_ID.getValue(), null);
        if (!StringUtils.isBlank(needCheckUserId) && !needCheckUserId.equals(userId)) {
            CacheOperatorInfo.setMapValue(CacheKeyName.VALIDATED_FACE_IMG.getValue(), null);
        }
        log.info("修改脸部图片-------------------------userid：" + userId);
        String cacheFace = (String) CacheOperatorInfo.getMapValue(CacheKeyName.VALIDATED_FACE_IMG.getValue(), null);
        if (!StringUtils.isBlank(face) && null == cacheFace) {
            //去调用验证是否是脸部验证接口
            log.info("调用验证接口start-------------------------");
            String validatedImg = this.validateIsFaceImg(face);
            log.info("第一次识别结果-------------------------" + (null != validatedImg));
            if (!StringUtils.isBlank(validatedImg)) {
                CacheOperatorInfo.setMapValue(CacheKeyName.CAHCE_NEED_CHECK_FACE_USER_ID.getValue(), userId);
                //接口调用
                CacheOperatorInfo.setMapValue(CacheKeyName.VALIDATED_FACE_IMG.getValue(), validatedImg);
                return ApiResult.fail("继续");
            }
            return ApiResult.fail("失败");
        } else if (!StringUtils.isBlank(face) && !StringUtils.isBlank(cacheFace) && imgsCompareTimes < 10) {
            //去调用验证是否是脸部验证接口
            String validatedImg = this.validateIsFaceImg(face);
            log.info("第二次识别结果------------------------" + (null != validatedImg));
            if (!StringUtils.isBlank(validatedImg)) {
                imgsCompareTimes++;
                //去调用比对的接口
                Boolean result = this.compareFaceImg((String) CacheOperatorInfo.getMapValue(CacheKeyName.VALIDATED_FACE_IMG.getValue(), null), validatedImg);
                log.info("比对结果-------------------------" + result);
                if (result) {
                    User u = userMapper.selectById(userId);
                    String oldFaceImg = u.getFaceImgs();
                    String imgName = saveFaceImg(userId, (String) CacheOperatorInfo.getMapValue(CacheKeyName.VALIDATED_FACE_IMG.getValue(), null));
                    u.setFaceImgs(imgName);
                    userMapper.updateById(u);
                    CacheOperatorInfo.setMapValue(CacheKeyName.VALIDATED_FACE_IMG.getValue(), null);
                    this.deleteFaceImg(oldFaceImg);
                    //commonSendInfo.sendUsers(userId);
                    return ApiResult.success();
                }
            }
            return ApiResult.fail("验证失败");
        } else if (imgsCompareTimes >= 10) {
            imgsCompareTimes = 0;
            //复位
            CacheOperatorInfo.setMapValue(CacheKeyName.VALIDATED_FACE_IMG.getValue(), null);
            return ApiResult.fail("请对准摄像头重新拍摄");
        }
        CacheOperatorInfo.setMapValue(CacheKeyName.VALIDATED_FACE_IMG.getValue(), null);
        return ApiResult.fail("失败");
    }

//	@Override
//	public ApiResult updateFaceInfo(Long userId,String face) {
//		String faceName = this.saveTempFaceImg(userId, face);
//		String cacheFace = (String)CacheOperatorInfo.getMapValue(CacheOperatorInfo.FACE_IMG, null);
//		if(!StringUtils.isBlank(faceName) && null == cacheFace) {
//			//去调用验证是否是脸部验证接口
//			String validatedImg = this.validateIsFaceImg(faceName);
//			if(!StringUtils.isBlank(validatedImg)) {
//				//接口调用
//				CacheOperatorInfo.setMapValue(CacheOperatorInfo.FACE_IMG, faceName);
//			}
//			return ApiResult.fail("继续");
//		}else if(!StringUtils.isBlank(faceName) && !StringUtils.isBlank(cacheFace) && imgsCompareTimes < 10) {
//			//去调用验证是否是脸部验证接口
//			String validatedImg = this.validateIsFaceImg(faceName);
//			if(!StringUtils.isBlank(validatedImg)) {
//				imgsCompareTimes ++;
//				//去调用比对的接口
//				Boolean result = this.compareFaceImg((String)CacheOperatorInfo.getMapValue(CacheOperatorInfo.FACE_IMG, null), faceName);
//				if(result) {
//					User u = userMapper.selectById(userId);
//					String oldFaceImg = u.getFaceImgs();
//					u.setFaceImgs((String)CacheOperatorInfo.getMapValue(CacheOperatorInfo.FACE_IMG, null));
//					userMapper.updateById(u);
//					CacheOperatorInfo.setMapValue(CacheOperatorInfo.FACE_IMG, null);
//					this.transImg(u.getFaceImgs());
//					this.deleteTempImg(faceName);
//					this.deleteFaceImg(oldFaceImg);
//					return ApiResult.success();
//				}
//			}
//			return ApiResult.fail("验证失败");
//		}else if(imgsCompareTimes >= 10) {
//			imgsCompareTimes = 0;
//			CacheOperatorInfo.setMapValue(CacheOperatorInfo.FACE_IMG, null);
//			return ApiResult.fail("请对准摄像头重新拍摄");
//		}
//		return ApiResult.fail("失败");
//	}

    /**
     * @param faceName
     * @return void
     * @description 验证是否脸部图片
     * @auther 韩兵
     * @Date 2020年7月24日
     */
    private String validateIsFaceImg(String faceName) {
        Map<String, String> param = new HashMap<String, String>();
        param.put("inFile", faceName.substring(22));
        param.put("fileExtension", "bmp");
        ResponseEntity<?> entity = null;
        try {
            entity = restBiz.postForEntity(appConfig.getCommunicationApiUrl() +
                            appConfig.getCommunicationFaceValidate(),
                    param, String.class, null);
            if (null != entity && entity.getStatusCode() == HttpStatus.OK) {
                String result = (String) entity.getBody();
                return result;
            }
        } catch (Exception e) {
            log.error("验证脸部图片异常", e);
            return null;
        }
        return null;
    }

    /**
     * @param faceImg
     * @param tempImg
     * @return
     * @return Boolean
     * @description 图片比较
     * @auther 韩兵
     * @Date 2020年7月24日
     */
    private Boolean compareFaceImg(String faceImg, String tempImg) {
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("faceFile2", faceImg);
        param.put("faceFile1", tempImg);
        ResponseEntity<?> entity = null;
        try {
            entity = restBiz.postForEntity(appConfig.getCommunicationApiUrl() +
                            appConfig.getCommunicationFaceCompare(),
                    param, Boolean.class, null);
            if (null != entity && entity.getStatusCode() == HttpStatus.OK) {
                return (Boolean) entity.getBody();
            }
        } catch (Exception e) {
            log.error("比较脸部图片异常", e);
            return false;
        }
        return false;
    }

    public String saveFaceImg(String userId, String base64Img) {
        OutputStream outputStream = null;
        String fileName = userId + "_" + System.currentTimeMillis() + ".bmp";
        File file = new File(appConfig.getRootPath() + FormatImgPre.PRE_FACE.getValue() + fileName);
        try {
            if (!file.createNewFile()) {
                log.error("保存人脸识别图片失败");
            }
            outputStream = new FileOutputStream(file.getPath());
            Decoder decoder = Base64.getDecoder();

            if (!StringUtils.isBlank(base64Img)) {
                //String imgBase64 = base64Img.substring(22);
                //转码
                byte[] bytes = decoder.decode(base64Img);
                //输入到文件里
                outputStream.write(bytes);
            }
            return fileName;
        } catch (IOException e) {
            log.error("用户管理异常", e);
        } finally {
            if (null != outputStream) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error("用户管理异常", e);
                }
            }
        }
        return null;
    }

//	@Override
//	public String saveTempFaceImg(Long userId, String base64Img) {
//		OutputStream outputStream = null;
//		String fileName = userId+"_"+System.currentTimeMillis()+".jpg";
//		File file = new File(appConfig.getTempImgPath()+"/"+fileName);
//        try {
//			file.createNewFile();
//			outputStream = new FileOutputStream(file.getPath());
//			Decoder decoder = Base64.getDecoder();
//
//			if(!StringUtils.isBlank(base64Img)) {
//				String imgBase64 = base64Img.substring(22);
//				//转码
//		        byte[] bytes = decoder.decode(imgBase64);
//		        //输入到文件里
//		        outputStream.write(bytes);
//			}
//			outputStream.close();
//			return fileName;
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//        return null;
//	}
//
//	//删除临时图片
//	private void deleteTempImg(String faceName) {
//		File file = new File(appConfig.getTempImgPath()+"/"+faceName);
//		if (file.exists()) {
//			file.delete();
//		}
//	}

    //删除脸部图片
    private void deleteFaceImg(String faceName) {
        File file = new File(appConfig.getRootPath() + FormatImgPre.PRE_FACE.getValue() + faceName);
        if (file.exists()) {
            if (!file.delete()) {
                log.error("删除图片异常");
            }
        }
    }

//	//转移图片
//	@Deprecated
//	private void transImg(String faceName) {
//		File file = new File(appConfig.getTempImgPath()+"/"+faceName);
//		try {
//			FileInputStream fis = new FileInputStream(file);
//			FileOutputStream fos = new FileOutputStream(new File(appConfig.getImgPath()+"/"+faceName));
//			byte[] read = new byte[1024];
//            int len = 0;
//            while((len = fis.read(read))!= -1){
//                fos.write(read,0,len);
//            }
//            fis.close();
//            fos.flush();
//            fos.close();
//            file.delete();
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//	}

    @Override
    public UserVO selectUserByUserId(String userId) {
        return userMapper.selectUserByUserId(userId);
    }

}
